﻿/**
 * @file MessageServer.hpp
 * @brief SSD仿真系统IPC消息服务器类，负责消息队列管理与响应处理。
 */
#pragma once
#ifndef __MessageServer_h__
#define __MeesageServer_h__

#include <memory>
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/deque.hpp>

#include "MessageBaseService.hpp"

using namespace boost::interprocess;

/**
 * @class MessageServer
 * @brief IPC消息服务器类模板，负责消息队列管理与响应处理。
 * @tparam TData 消息数据类型
 */
template <typename TData>
class MessageServer : public MessageBaseService<TData>
{
public:
    /**
     * @brief 构造函数，连接到已存在的共享内存消息服务器。
     * @param serverName 服务器名称
     * @throws const char* 服务器不存在时抛出异常
     */
    MessageServer(const char *serverName)
    {
        managed_shared_memory *sharedMemory;
        try
        {
            sharedMemory = new managed_shared_memory(open_only, serverName);
        }
        catch (...)
        {
            throw "Server does not exist";
        }

        MessageBaseService<TData>::_ManagedShm = std::unique_ptr<managed_shared_memory>(sharedMemory);
        MessageBaseService<TData>::_Counter = MessageBaseService<TData>::_ManagedShm->find<MessageId>(COUNTER).first;
        MessageBaseService<TData>::_Queue = MessageBaseService<TData>::_ManagedShm->find<MessageQueue>(QUEUE).first;
        MessageBaseService<TData>::_ResponseQueue = MessageBaseService<TData>::_ManagedShm->find<MessageQueue>(RESPONSE_QUEUE).first;
    }

    /**
     * @brief 构造函数，创建或连接共享内存消息服务器。
     * @param serverName 服务器名称
     * @param size 共享内存大小
     * @param force 是否强制移除已存在的同名共享内存
     * @throws const char* 共享内存已存在时抛出异常
     */
    MessageServer(const char *serverName, const U32 &size, bool force = true)
    {
        if (force)
        {
            shared_memory_object::remove(serverName);
        }

        try
        {
            MessageBaseService<TData>::_ManagedShm = std::unique_ptr<managed_shared_memory>(new managed_shared_memory(open_or_create, serverName, size));
        }
        catch (...)
        {
            throw "Shared memory with the name " + std::string(serverName) + " already exists";
        }

        SynchronizedQueue<MessageId>::allocator_type alloc(MessageBaseService<TData>::_ManagedShm->get_segment_manager());
        SynchronizedQueue<MessageId>::allocator_type alloc1(MessageBaseService<TData>::_ManagedShm->get_segment_manager());

        MessageBaseService<TData>::_Counter = MessageBaseService<TData>::_ManagedShm->construct<MessageId>(COUNTER)(0);
        MessageBaseService<TData>::_Queue = MessageBaseService<TData>::_ManagedShm->construct<MessageQueue>(QUEUE)(alloc);
        MessageBaseService<TData>::_ResponseQueue = MessageBaseService<TData>::_ManagedShm->construct<MessageQueue>(RESPONSE_QUEUE)(alloc1);
    }

    /**
     * @brief 检查是否有待处理消息。
     * @return 是否有消息
     */
    bool HasMessage()
    {
        return !MessageBaseService<TData>::_Queue->empty();
    }

    /**
     * @brief 弹出待处理消息。
     * @return 消息指针
     */
    Message<TData> *Pop()
    {
        return MessageBaseService<TData>::DoPop(MessageBaseService<TData>::_Queue);
    }

    /**
     * @brief 推送响应消息到响应队列。
     * @param message 消息指针
     * @throws const char* 消息不需要响应时抛出异常
     */
    void PushResponse(Message<TData> *message)
    {
        if (!message->ExpectsResponse())
        {
            throw "This message doesn't need respond";
        }

        message->_ResponseTime = std::chrono::high_resolution_clock::now();
        MessageBaseService<TData>::DoPush(MessageBaseService<TData>::_ResponseQueue, message);
    }

    /**
     * @brief 根据消息ID推送响应消息。
     * @param id 消息ID
     */
    void PushResponse(const MessageId &id)
    {
        Message<TData> *message = GetMessage(id);
        PushResponse(message);
    }

    /**
     * @brief 释放消息对象及其载荷。
     * @param message 要释放的消息指针
     * @throws const char* 消息需要响应时抛出异常
     */
    void DeallocateMessage(Message<TData> *message)
    {
        if (message->ExpectsResponse())
        {
            throw "This message needs respond";
        }

        MessageBaseService<TData>::DoDeallocateMessage(message);
    }

    /**
     * @brief 根据消息ID释放消息对象。
     * @param id 消息ID
     */
    void DeallocateMessage(const MessageId &id)
    {
        Message<TData> *message = GetMessage(id);
        DeallocateMessage(message);
    }

    /**
     * @brief 根据消息ID查找消息。
     * @param id 消息ID
     * @return 消息指针
     */
    Message<TData> *GetMessage(const MessageId &id)
    {
        return MessageBaseService<TData>::GetMessage(id);
    }
};

#endif